﻿// *************************************************************************************************
// Project: RealSense.Light.Core
// Namespace: RealSense.Light.Core
// File: VoiceBuilder.cs  Author: Peter O'Hanlon
// Copyright © Peter O'Hanlon 2014-2015
// Date: 2015/1/5 22:02
// *************************************************************************************************
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Media;
using System.Text;
using System.Threading.Tasks;

namespace RealSense.Light.Core
{
  internal class AudioDetails
  {
    public const int ChunkIdRiff = 0x46464952;
    public const int ChunkDataSizeRiff = 0;
    public const int RiffType = 0x45564157;
    public const int ChunkIdFormat = 0x20746d66;
    public const int ChunkDataSizeFormat = 0x12;
    public const short CompressionCode = 1;
    public const short SignificantBitsPerSample = 16;
    public const short ExtraFormatSize = 0;
    public const int ChunkIdData = 0x61746164;
    public const int ChunkIdSizeData = 0;
  }

  internal class VoiceBuilder : RealSenseBase
  {
    private MemoryStream stream;
    private BinaryWriter writer;

    public VoiceBuilder(int numberOfChannels, int sampleRate)
    {
      stream = new MemoryStream();
      writer = new BinaryWriter(stream);

      Write(AudioDetails.ChunkIdRiff);
      Write(AudioDetails.ChunkDataSizeRiff);
      Write(AudioDetails.RiffType);
      Write(AudioDetails.ChunkIdFormat);
      Write(AudioDetails.ChunkDataSizeFormat);
      Write(AudioDetails.CompressionCode);
      Write((short)numberOfChannels);
      Write(sampleRate);
      Write(sampleRate * 2 * numberOfChannels);
      Write((short)(numberOfChannels * 2));
      Write(AudioDetails.SignificantBitsPerSample);
      Write(AudioDetails.ExtraFormatSize);
      Write(AudioDetails.ChunkIdData);
      Write(AudioDetails.ChunkIdSizeData);
    }

    public void WriteToAudioStream(PXCMAudio audio)
    {
      PXCMAudio.AudioData audioData = null;
      InvokeAndThrow(() => audio.AcquireAccess(PXCMAudio.Access.ACCESS_READ,
        PXCMAudio.AudioFormat.AUDIO_FORMAT_PCM,
        out audioData));

      try
      {
        writer.Write(audioData.ToByteArray());
      }
      finally
      {
        audio.ReleaseAccess(audioData);
      }
    }

    public void Close()
    {
      long position = writer.Seek(0, SeekOrigin.Current);

      try
      {
        writer.Seek(0x2a, SeekOrigin.Begin);
        Write((int)position - 46);
        writer.Seek(0x04, SeekOrigin.Begin);
        Write((int)position - 8);
        writer.Seek(0, SeekOrigin.Begin);

        stream.Position = 0;

        using (SoundPlayer player = new SoundPlayer(stream))
        {
          player.PlaySync();
        }
      }
      finally
      {
        stream.Dispose();
        writer.Dispose();
        writer = null;
      }
    }

    private void Write(int value)
    {
      writer.Write(value);
    }

    private void Write(short value)
    {
      writer.Write(value);
    }

    protected override void Dispose(bool disposing)
    {
      if (writer != null)
      {
        Close();
      }
    }
  }
}
